home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-30  |  6.3 KB  |  282 lines

  1. /* General purpose software timer facilities
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "timer.h"
  7. #include "proc.h"
  8. #include "mbuf.h"
  9. #include "commands.h"
  10. #include "daemon.h"
  11. #include "hardware.h"
  12. #include "socket.h"
  13.  
  14. /* Head of running timer chain.
  15.  * The list of running timers is sorted in increasing order of expiration;
  16.  * i.e., the first timer to expire is always at the head of the list.
  17.  */
  18. struct timer *Timers;
  19.  
  20. static void t_alarm __ARGS((void *x));
  21.  
  22. /* Process that handles clock ticks */
  23. void
  24. timerproc(i,v1,v2)
  25. int i;
  26. void *v1,*v2;
  27. {
  28.     register struct timer *t, *p;
  29.     register struct timer *expired;
  30.     char i_state;
  31.     int tmp;
  32.     void (**vf)();
  33.  
  34.     for(;;){
  35.         /* Atomic read and decrement of Tick */
  36.         for(;;){
  37.             i_state = dirps();
  38.             tmp = Tick;
  39.             if(tmp != 0){
  40.                 Tick--;
  41.                 restore(i_state);
  42.                 break;
  43.             }    
  44.             restore(i_state);
  45.             pwait(&Tick);
  46.         }
  47. #ifndef TNOS_68K
  48.         if(!istate()){
  49.             restore(1);
  50.             printf("timer: ints were off!\n");
  51.             fflush(stdout);        /* make sure it gets out */
  52.         }
  53. #endif
  54.  
  55.         /* Call the functions listed in config.c */
  56.         for(vf = Cfunc;*vf != NULL;vf++)
  57.             (*vf)();
  58.  
  59.         tflush();    /* Flush current session output */
  60.         pwait(NULL);    /* Let them all do their writes */
  61.         rflush();    /* Flush out buffered console stuff */
  62.         fflush(stdout);    /* And flush out stdout too */
  63.  
  64.         if(Timers == NULLTIMER)
  65.             continue;    /* No active timers, all done */
  66.  
  67.         /* Initialize null expired timer list */
  68.         expired = NULLTIMER;
  69.  
  70.         /* Move expired timers to expired list. Note use of
  71.          * subtraction and comparison to zero rather than the
  72.          * more obvious simple comparison; this avoids
  73.          * problems when the clock count wraps around.
  74.          */
  75.         while(Timers != NULLTIMER && (Clock - Timers->expiration) >= 0){
  76.             if(Timers->next == Timers){
  77.                 printf("PANIC: Timer loop at %lx\n",
  78.                  (long)Timers);
  79.                 iostop();
  80.                 exit(1);
  81.             }
  82.             /* Save Timers since stop_timer will change it */
  83.             t = Timers;
  84.             stop_timer(t);
  85.             /* Add to expired timer list */
  86.             if(expired == NULLTIMER){
  87.                 expired = t;
  88.             } else {
  89.                 for(p = expired ; p->next != NULLTIMER ; p = p->next);
  90.                 p->next = t;    /* place at end of chain */
  91.             }
  92.             t->next = NULLTIMER;
  93.         }
  94.         /* Now go through the list of expired timers, removing each
  95.          * one and kicking the notify function, if there is one
  96.          * Note that the state should ne TIMER_STOP. We just stopped
  97.          * it remember? Now is someone else changed it, ignore timer.
  98.          */
  99.         while((t = expired) != NULLTIMER){
  100.             expired = t->next;
  101.             if(t->state == TIMER_STOP){
  102.                 t->state = TIMER_EXPIRE;
  103.                 if(t->func)
  104.                     (*t->func)(t->arg);
  105.             }
  106.         }
  107.         pwait(NULL);    /* Let them run before handling more ticks */
  108.     }
  109. }
  110. /* Start a timer */
  111. void
  112. start_timer(t)
  113. struct timer *t;
  114. {
  115.     register struct timer *tnext;
  116.     struct timer *tprev = NULLTIMER;
  117.  
  118.     if(t == NULLTIMER)
  119.         return;
  120.     if(t->state == TIMER_RUN)
  121.         stop_timer(t);
  122.     if(t->duration == 0)
  123.         return;        /* A duration value of 0 disables the timer */
  124.  
  125.     t->expiration = Clock + t->duration;
  126.     t->state = TIMER_RUN;
  127.  
  128.     /* Find right place on list for this guy. Once again, note use
  129.      * of subtraction and comparison with zero rather than direct
  130.      * comparison of expiration times.
  131.      */
  132.     for(tnext = Timers;tnext != NULLTIMER;tprev=tnext,tnext = tnext->next){
  133.         if((tnext->expiration - t->expiration) >= 0)
  134.             break;
  135.     }
  136.     /* At this point, tprev points to the entry that should go right
  137.      * before us, and tnext points to the entry just after us. Either or
  138.      * both may be null.
  139.      */
  140.     if(tprev == NULLTIMER)
  141.         Timers = t;        /* Put at beginning */
  142.     else
  143.         tprev->next = t;
  144.  
  145.     t->next = tnext;
  146. }
  147. /* Stop a timer */
  148. void
  149. stop_timer(timer)
  150. struct timer *timer;
  151. {
  152.     register struct timer *t;
  153.     struct timer *tlast = NULLTIMER;
  154.  
  155.     if(timer == NULLTIMER || timer->state != TIMER_RUN)
  156.         return;
  157.  
  158.     /* Verify that timer is really on list */
  159.     for(t = Timers;t != NULLTIMER;tlast = t,t = t->next)
  160.         if(t == timer)
  161.             break;
  162.  
  163.     if(t == NULLTIMER)
  164.         return;        /* Should probably panic here */
  165.  
  166.     /* Delete from active timer list */
  167.     if(tlast != NULLTIMER)
  168.         tlast->next = t->next;
  169.     else
  170.         Timers = t->next;    /* Was first on list */
  171.  
  172.     t->state = TIMER_STOP;
  173. }
  174. /* Return milliseconds remaining on this timer */
  175. int32
  176. read_timer(t)
  177. struct timer *t;
  178. {
  179.     int32 remaining;
  180.  
  181.     if(t == NULLTIMER || t->state != TIMER_RUN)
  182.         return 0;
  183.     remaining = t->expiration - Clock;
  184.     if(remaining <= 0)
  185.         return 0;    /* Already expired */
  186.     else
  187.         return remaining * MSPTICK;
  188. }
  189. void
  190. set_timer(t,interval)
  191. struct timer *t;
  192. int32 interval;
  193. {
  194. #ifndef TNOS_68K
  195. #define FUDGE 1
  196. #else
  197. #define FUDGE 0
  198. #endif
  199.  
  200.     if(t == NULLTIMER)
  201.         return;
  202.     /* Round the interval up to the next full tick, and then
  203.      * add another tick to guarantee that the timeout will not
  204.      * occur before the interval is up. This is necessary because
  205.      * we're asynchonous with the system clock.
  206.      */
  207.     if(interval != 0)
  208.         t->duration = FUDGE + (interval + MSPTICK - 1)/MSPTICK;
  209.     else
  210.         t->duration = 0;
  211. }
  212. /* Delay process for specified number of milliseconds.
  213.  * Normally returns 0; returns -1 if aborted by alarm.
  214.  */
  215. int
  216. mspause(ms)
  217. int32 ms;
  218. {
  219.     int val;
  220.  
  221.     if(Curproc == NULLPROC || ms == 0)
  222.         return 0;
  223.     alarm(ms);
  224.     /* The actual event doesn't matter, since we'll be alerted */
  225.     while(Curproc->alarm.state == TIMER_RUN){
  226.         if((val = pwait(Curproc)) != 0)
  227.             break;
  228.     }
  229.     alarm(0L); /* Make sure it's stopped, in case we were killed */    
  230.     return (val == EALARM) ? 0 : -1;
  231. }
  232. static void
  233. t_alarm(x)
  234. void *x;
  235. {
  236.     alert((struct proc *)x,EALARM);
  237. }
  238. /* Send signal to current process after specified number of milliseconds */
  239. void
  240. alarm(ms)
  241. int32 ms;
  242. {
  243.     if(Curproc != NULLPROC){
  244.         set_timer(&Curproc->alarm,ms);
  245.         Curproc->alarm.func = t_alarm;
  246.         Curproc->alarm.arg = (char *)Curproc;
  247.         start_timer(&Curproc->alarm);
  248.     }
  249. }
  250. /* Convert time count in seconds to printable days:hr:min:sec format */
  251. char *
  252. tformat(t)
  253. int32 t;
  254. {
  255.     static char buf[17],*cp;
  256.     unsigned int days,hrs,mins,secs;
  257.     int minus;
  258.  
  259.     if(t < 0){
  260.         t = -t;
  261.         minus = 1;
  262.     } else
  263.         minus = 0;
  264.  
  265.     secs = t % 60;
  266.     t /= 60;
  267.     mins = t % 60;
  268.     t /= 60;
  269.     hrs = t % 24;
  270.     t /= 24;
  271.     days = t;
  272.     if(minus){
  273.         cp = buf+1;
  274.         buf[0] = '-';
  275.     } else
  276.         cp = buf;
  277.     sprintf(cp,"%u:%02u:%02u:%02u",days,hrs,mins,secs);
  278.     
  279.     return buf;
  280. }
  281.     
  282.